using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Web.UI;
using System.Web;
using System.Security.Permissions;
using System;
using System.Collections.Generic;
using System.Collections;
using System.Globalization;

namespace SharpPieces.Web.Controls
{

    /// <summary>
    /// Represents a tag cloud control.
    /// </summary>
    [ToolboxData("<{0}:TagCloud runat=\"server\"></{0}:TagCloud>"), SupportsEventValidation]
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class TagCloud : DataBoundControl, INamingContainer
    {

        // Fields

        private IList<Control> tagControls = new List<Control>();

        // Methods

        /// <summary>
        /// Retrieves data from the associated data source.
        /// </summary>
        protected override void PerformSelect()
        {
            // raise data binding event if neccesary

            if (this.IsBoundUsingDataSourceID)
            {
                this.OnDataBinding(EventArgs.Empty);
            }

            // get the source

            this.GetData().Select(this.CreateDataSourceSelectArguments(), this.OnDataSourceViewSelectCallback);

            // data binding completed

            this.RequiresDataBinding = false;
            this.MarkAsDataBound();

            // do data bound

            this.OnDataBound(EventArgs.Empty);
        }

        private void OnDataSourceViewSelectCallback(IEnumerable data)
        {
            this.PerformDataBinding(data);
        }

        /// <summary>
        /// When overridden in a derived class, binds data from the data source to the control.
        /// </summary>
        /// <param name="data">The <see cref="T:System.Collections.IEnumerable"/> list of data returned from a <see cref="M:System.Web.UI.WebControls.DataBoundControl.PerformSelect"/> method call.</param>
        protected override void PerformDataBinding(IEnumerable data)
        {
            base.PerformDataBinding(data);

            // clear the tag controls

            this.tagControls.Clear();

            // bind the values according to the tag type

            if (!this.DesignMode)
            {
                int noVisible = (this.HyperLink.Visible ? 1 : 0) + (this.LinkButton.Visible ? 1 : 0);

                if ((1 < noVisible) || (1 > noVisible))
                {
                    throw new NotSupportedException("Tag cloud should have at least one tag render type and not more.");
                }
            }

            if (this.HyperLink.Visible)
            {
                foreach (object dataItem in data)
                {
                    HyperLink link = new HyperLink();

                    if (!string.IsNullOrEmpty(this.HyperLink.DataTextValue))
                    {
                        link.Text = this.FormatOneDataValue(
                            DataBinder.GetPropertyValue(dataItem, this.HyperLink.DataTextValue, null),
                            this.HyperLink.DataTextFormatString);
                    }
                    else
                    {
                        PropertyDescriptorCollection props = TypeDescriptor.GetProperties(dataItem);

                        if (0 < props.Count)
                        {
                            link.Text = this.FormatOneDataValue(
                                props[0].GetValue(dataItem),
                                this.HyperLink.DataTextFormatString);
                        }
                        else
                        {
                            link.Text = string.Empty;
                        }
                    }

                    if (!string.IsNullOrEmpty(this.HyperLink.DataUrlValue))
                    {
                        link.NavigateUrl = this.FormatOneDataValue(
                            DataBinder.GetPropertyValue(dataItem, this.HyperLink.DataUrlValue, null),
                            this.HyperLink.DataUrlFormatString);
                    }

                    link.CssClass = this.HyperLink.CssClass;

                    link.Target = this.HyperLink.Target;

                    this.tagControls.Add(link);
                }
            }
            else if (this.LinkButton.Visible)
            {
                foreach (object dataItem in data)
                {
                    LinkButton button = new LinkButton();

                    if (!string.IsNullOrEmpty(this.LinkButton.DataTextValue))
                    {
                        button.Text = this.FormatOneDataValue(
                            DataBinder.GetPropertyValue(dataItem, this.LinkButton.DataTextValue, null),
                            this.LinkButton.DataTextFormatString);
                    }
                    else
                    {
                        PropertyDescriptorCollection props = TypeDescriptor.GetProperties(dataItem);

                        if (0 < props.Count)
                        {
                            button.Text = this.FormatOneDataValue(
                                props[0].GetValue(dataItem),
                                this.LinkButton.DataTextFormatString);
                        }
                        else
                        {
                            button.Text = string.Empty;
                        }
                    }

                    if (!string.IsNullOrEmpty(this.LinkButton.DataCommandArgumentValue))
                    {
                        button.CommandArgument = this.FormatOneDataValue(
                            DataBinder.GetPropertyValue(dataItem, this.LinkButton.DataCommandArgumentValue, null),
                            this.LinkButton.DataCommandArgumentFormatString);
                    }

                    button.CssClass = this.LinkButton.CssClass;

                    button.CommandName = this.LinkButton.CommandName;

                    this.tagControls.Add(button);
                }
            }
        }

        /// <summary>
        /// Handles the <see cref="E:System.Web.UI.Control.PreRender"/> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            foreach (Control tag in this.tagControls)
            {
                this.Controls.Add(tag);
            }            
        }

        /// <summary>
        /// Formats one data value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="format">The value format.</param>
        /// <returns>The formated value.</returns>
        private string FormatOneDataValue(object value, string format)
        {
            if ((null == value) || Convert.IsDBNull(value))
            {
                return null;
            }

            if (string.IsNullOrEmpty(format))
            {
                return string.Format("{0}", value);
            }

            return string.Format(CultureInfo.CurrentCulture, format, new object[] { value });
        }

        // Properties

        /// <summary>
        /// Gets or sets the tag as hyper link.
        /// </summary>
        /// <value>The tag as hyper link.</value>
        [Description("The tag as hyper link."), Category("Default"), DefaultValue(""), MergableProperty(false)]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public virtual TagHyperLink HyperLink
        {
            get
            {
                if (null == this.ViewState["HyperLink"])
                {
                    TagHyperLink link = new TagHyperLink();
                    if (this.EnableViewState)
                    {
                        link.TrackViewState();
                    }
                    this.ViewState["HyperLink"] = link;
                }
                return (TagHyperLink)this.ViewState["HyperLink"];
            }
            set
            {
                if ((null != value) && this.EnableViewState)
                {
                    value.TrackViewState();
                }
                this.ViewState["HyperLink"] = value;
            }
        }

        /// <summary>
        /// Gets or sets the tag as link button.
        /// </summary>
        /// <value>The tag as link button.</value>
        [Description("The tag as link button."), Category("Default"), DefaultValue(""), MergableProperty(false)]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public virtual TagLinkButton LinkButton
        {
            get
            {
                if (null == this.ViewState["LinkButton"])
                {
                    TagLinkButton button = new TagLinkButton();
                    if (this.EnableViewState)
                    {
                        button.TrackViewState();
                    }
                    this.ViewState["LinkButton"] = button;
                }
                return (TagLinkButton)this.ViewState["LinkButton"];
            }
            set
            {
                if ((null != value) && this.EnableViewState)
                {
                    value.TrackViewState();
                }
                this.ViewState["LinkButton"] = value;
            }
        }

    }


    /// <summary>
    /// Represents a tag hyperlink representation.
    /// </summary>
    [Serializable]
    [TypeConverter(typeof(ExpandableObjectConverter)), DefaultProperty("DataTextValue"), Themeable(false)]
    public class TagHyperLink : IStateManager
    {

        // Fields

        private bool tracks;
        private DirtyFlags dirtyFlags = DirtyFlags.None;
        private string dataTextValue = null;
        private string dataTextFormatString = null;
        private string dataUrlValue = null;
        private string dataUrlFormatString = null;
        private bool visible = false;
        private string cssClass = null;
        private string target = null;

        // Methods

        /// <summary>
        /// Initializes a new instance of the <see cref="TagHyperLink"/> class.
        /// </summary>
        public TagHyperLink()
        {
        }

        /// <summary>
        /// When implemented by a class, gets a value indicating whether a server control is tracking its view state changes.
        /// </summary>
        /// <value></value>
        /// <returns>true if a server control is tracking its view state changes; otherwise, false.</returns>
        internal bool IsTrackingViewState
        {
            get { return this.tracks; }
        }

        /// <summary>
        /// When implemented by a class, loads the server control's previously saved view state to the control.
        /// </summary>
        /// <param name="state">An <see cref="T:System.Object"></see> that contains the saved view state values for the control.</param>
        internal virtual void LoadViewState(object state)
        {
            if (null != state)
            {
                object[] s = state as object[];
                if (null != s[0])
                {
                    this.DataTextValue = (string)s[0];
                }
                if (null != s[1])
                {
                    this.DataTextFormatString = (string)s[1];
                }
                if (null != s[2])
                {
                    this.DataUrlValue = (string)s[2];
                }
                if (null != s[3])
                {
                    this.DataUrlFormatString = (string)s[3];
                }
                if (null != s[4])
                {
                    this.Visible = (bool)s[4];
                }
                if (null != s[5])
                {
                    this.CssClass = (string)s[5];
                }
                if (null != s[6])
                {
                    this.Target = (string)s[6];
                }
            }
        }

        /// <summary>
        /// When implemented by a class, saves the changes to a server control's view state to an <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// The <see cref="T:System.Object"></see> that contains the view state changes.
        /// </returns>
        internal virtual object SaveViewState()
        {
            object[] state = new object[5];

            state[0] = ((this.dirtyFlags & DirtyFlags.DataTextValue) == DirtyFlags.DataTextValue) ? this.DataTextValue : null;
            state[1] = ((this.dirtyFlags & DirtyFlags.DataTextFormatString) == DirtyFlags.DataTextFormatString) ? this.DataTextFormatString : null;
            state[2] = ((this.dirtyFlags & DirtyFlags.DataUrlValue) == DirtyFlags.DataUrlValue) ? this.DataUrlValue : null;
            state[3] = ((this.dirtyFlags & DirtyFlags.DataUrlFormatString) == DirtyFlags.DataUrlFormatString) ? this.DataUrlFormatString : null;
            state[4] = ((this.dirtyFlags & DirtyFlags.Visible) == DirtyFlags.Visible) ? (object)this.Visible : (object)null;
            state[5] = ((this.dirtyFlags & DirtyFlags.CssClass) == DirtyFlags.CssClass) ? this.CssClass : null;
            state[6] = ((this.dirtyFlags & DirtyFlags.Target) == DirtyFlags.Target) ? this.Target : null;

            return state;
        }

        /// <summary>
        /// When implemented by a class, instructs the server control to track changes to its view state.
        /// </summary>
        internal void TrackViewState()
        {
            this.tracks = true;
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </returns>
        public override string ToString()
        {
            return string.Format("[{0}]", this.DataTextValue);
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"></see> is equal to the current <see cref="T:System.Object"></see>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"></see> to compare with the current <see cref="T:System.Object"></see>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"></see> is equal to the current <see cref="T:System.Object"></see>; otherwise, false.
        /// </returns>
        public override bool Equals(object obj)
        {
            if ((null == obj) || (typeof(TagHyperLink) != obj.GetType()))
            {
                return false;
            }

            TagHyperLink text = (TagHyperLink)obj;

            return
                (this.DataTextValue == text.DataTextValue) &&
                (this.DataTextFormatString == text.DataTextFormatString) &&
                (this.DataUrlFormatString == text.DataUrlFormatString) &&
                (this.DataUrlFormatString == text.DataUrlFormatString) &&
                (this.Visible == text.Visible) &&
                (this.CssClass == text.CssClass) &&
                (this.Target == text.Target);
        }

        /// <summary>
        /// Serves as a hash function for a particular type. <see cref="M:System.Object.GetHashCode"></see> is suitable for use in hashing algorithms and data structures like a hash table.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"></see>.
        /// </returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }


        // Properties

        /// <summary>
        /// Gets or sets the data text value.
        /// </summary>
        /// <value>The data text value.</value>
        [Description("The data text value."), DefaultValue(null), NotifyParentProperty(true)]
        public string DataTextValue
        {
            get { return this.dataTextValue; }
            set
            {
                this.dataTextValue = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.DataTextValue;
                }
            }
        }

        /// <summary>
        /// Gets or sets the data text format string.
        /// </summary>
        /// <value>The data text format string.</value>
        [Description("The data text format string."), DefaultValue(null), NotifyParentProperty(true)]
        public string DataTextFormatString
        {
            get { return this.dataTextFormatString; }
            set
            {
                this.dataTextFormatString = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.DataTextFormatString;
                }
            }
        }

        /// <summary>
        /// Gets or sets the data URL value.
        /// </summary>
        /// <value>The data URL value.</value>
        [Description("The data URL value."), DefaultValue(null), NotifyParentProperty(true)]
        public string DataUrlValue
        {
            get { return this.dataUrlValue; }
            set
            {
                this.dataUrlValue = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.DataUrlValue;
                }
            }
        }

        /// <summary>
        /// Gets or sets the data URL format string.
        /// </summary>
        /// <value>The data URL format string.</value>
        [Description("The data URL format string."), DefaultValue(null), NotifyParentProperty(true)]
        public string DataUrlFormatString
        {
            get { return this.dataUrlFormatString; }
            set
            {
                this.dataUrlFormatString = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.DataUrlFormatString;
                }
            }
        }

        /// <summary>
        /// Gets or sets the visibility.
        /// </summary>
        /// <value>The visibility.</value>
        [Description("The visibility."), DefaultValue(false), NotifyParentProperty(true)]
        public bool Visible
        {
            get { return this.visible; }
            set
            {
                this.visible = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.Visible;
                }
            }
        }

        /// <summary>
        /// Gets or sets the CSS class.
        /// </summary>
        /// <value>The CSS class.</value>
        [Description("The CSS class."), DefaultValue(null), NotifyParentProperty(true)]
        public string CssClass
        {
            get { return this.cssClass; }
            set
            {
                this.cssClass = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.CssClass;
                }
            }
        }

        /// <summary>
        /// Gets or sets the link target.
        /// </summary>
        /// <value>The link target.</value>
        [TypeConverter(typeof(TargetConverter))]        
        [Description("The link target."), DefaultValue(null), NotifyParentProperty(true)]
        public string Target
        {
            get { return this.target; }
            set
            {
                this.target = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.Target;
                }
            }
        }

        // Nested Types

        private enum DirtyFlags
        {
            None = 0,
            DataTextValue = 1,
            DataTextFormatString = 2,
            DataUrlValue = 4,
            DataUrlFormatString = 8,
            Visible = 16,
            CssClass = 32,
            Target = 64
        }


        #region IStateManager Members

        /// <summary>
        /// When implemented by a class, gets a value indicating whether a server control is tracking its view state changes.
        /// </summary>
        /// <value></value>
        /// <returns>true if a server control is tracking its view state changes; otherwise, false.</returns>
        bool IStateManager.IsTrackingViewState
        {
            get { return this.IsTrackingViewState; }
        }

        /// <summary>
        /// When implemented by a class, loads the server control's previously saved view state to the control.
        /// </summary>
        /// <param name="state">An <see cref="T:System.Object"></see> that contains the saved view state values for the control.</param>
        void IStateManager.LoadViewState(object state)
        {
            this.LoadViewState(state);
        }

        /// <summary>
        /// When implemented by a class, saves the changes to a server control's view state to an <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// The <see cref="T:System.Object"></see> that contains the view state changes.
        /// </returns>
        object IStateManager.SaveViewState()
        {
            return this.SaveViewState();
        }

        /// <summary>
        /// When implemented by a class, instructs the server control to track changes to its view state.
        /// </summary>
        void IStateManager.TrackViewState()
        {
            this.TrackViewState();
        }

        #endregion

    }


    /// <summary>
    /// Represents a tag link button representation.
    /// </summary>
    [Serializable]
    [TypeConverter(typeof(ExpandableObjectConverter)), DefaultProperty("DataTextValue"), Themeable(false)]
    public class TagLinkButton : IStateManager
    {

        // Fields

        private bool tracks;
        private DirtyFlags dirtyFlags = DirtyFlags.None;
        private string dataTextValue = null;
        private string dataTextFormatString = null;
        private string dataCommandArgumentValue = null;
        private string dataCommandArgumentFormatString = null;
        private bool visible = false;
        private string cssClass = null;
        private string commandName = null;

        // Events

        /// <summary>
        /// Occurs when the TagLinkButton control is clicked.
        /// </summary>
        public event EventHandler Click;

        /// <summary>
        /// Occurs when the Command control is clicked.
        /// </summary>
        public event CommandEventHandler Command;

        // Methods

        /// <summary>
        /// Initializes a new instance of the <see cref="TagHyperLink"/> class.
        /// </summary>
        public TagLinkButton()
        {
        }

        /// <summary>
        /// When implemented by a class, gets a value indicating whether a server control is tracking its view state changes.
        /// </summary>
        /// <value></value>
        /// <returns>true if a server control is tracking its view state changes; otherwise, false.</returns>
        internal bool IsTrackingViewState
        {
            get { return this.tracks; }
        }

        /// <summary>
        /// When implemented by a class, loads the server control's previously saved view state to the control.
        /// </summary>
        /// <param name="state">An <see cref="T:System.Object"></see> that contains the saved view state values for the control.</param>
        internal virtual void LoadViewState(object state)
        {
            if (null != state)
            {
                object[] s = state as object[];
                if (null != s[0])
                {
                    this.DataTextValue = (string)s[0];
                }
                if (null != s[1])
                {
                    this.DataTextFormatString = (string)s[1];
                }
                if (null != s[2])
                {
                    this.DataCommandArgumentValue = (string)s[2];
                }
                if (null != s[3])
                {
                    this.DataCommandArgumentFormatString = (string)s[3];
                }
                if (null != s[4])
                {
                    this.Visible = (bool)s[4];
                }
                if (null != s[5])
                {
                    this.CssClass = (string)s[5];
                }
                if (null != s[6])
                {
                    this.CommandName = (string)s[6];
                }
            }
        }

        /// <summary>
        /// When implemented by a class, saves the changes to a server control's view state to an <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// The <see cref="T:System.Object"></see> that contains the view state changes.
        /// </returns>
        internal virtual object SaveViewState()
        {
            object[] state = new object[5];

            state[0] = ((this.dirtyFlags & DirtyFlags.DataTextValue) == DirtyFlags.DataTextValue) ? this.DataTextValue : null;
            state[1] = ((this.dirtyFlags & DirtyFlags.DataTextFormatString) == DirtyFlags.DataTextFormatString) ? this.DataTextFormatString : null;
            state[2] = ((this.dirtyFlags & DirtyFlags.DataCommandArgumentValue) == DirtyFlags.DataCommandArgumentValue) ? this.DataCommandArgumentValue : null;
            state[3] = ((this.dirtyFlags & DirtyFlags.DataCommandArgumentFormatString) == DirtyFlags.DataCommandArgumentFormatString) ? this.DataCommandArgumentFormatString : null;
            state[4] = ((this.dirtyFlags & DirtyFlags.Visible) == DirtyFlags.Visible) ? (object)this.Visible : (object)null;
            state[5] = ((this.dirtyFlags & DirtyFlags.CssClass) == DirtyFlags.CssClass) ? this.CssClass : null;
            state[6] = ((this.dirtyFlags & DirtyFlags.CommandName) == DirtyFlags.CommandName) ? this.CommandName : null;

            return state;
        }

        /// <summary>
        /// When implemented by a class, instructs the server control to track changes to its view state.
        /// </summary>
        internal void TrackViewState()
        {
            this.tracks = true;
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </returns>
        public override string ToString()
        {
            return string.Format("[{0}]", this.DataTextValue);
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"></see> is equal to the current <see cref="T:System.Object"></see>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"></see> to compare with the current <see cref="T:System.Object"></see>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"></see> is equal to the current <see cref="T:System.Object"></see>; otherwise, false.
        /// </returns>
        public override bool Equals(object obj)
        {
            if ((null == obj) || (typeof(TagLinkButton) != obj.GetType()))
            {
                return false;
            }

            TagLinkButton text = (TagLinkButton)obj;

            return
                (this.DataTextValue == text.DataTextValue) &&
                (this.DataTextFormatString == text.DataTextFormatString) &&
                (this.DataCommandArgumentValue == text.DataCommandArgumentValue) &&
                (this.DataCommandArgumentFormatString == text.DataCommandArgumentFormatString) &&
                (this.Visible == text.Visible) &&
                (this.CssClass == text.CssClass) &&
                (this.CommandName == text.CommandName);
        }

        /// <summary>
        /// Serves as a hash function for a particular type. <see cref="M:System.Object.GetHashCode"></see> is suitable for use in hashing algorithms and data structures like a hash table.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"></see>.
        /// </returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }


        // Properties

        /// <summary>
        /// Gets or sets the data text value.
        /// </summary>
        /// <value>The data text value.</value>
        [Description("The data text value."), DefaultValue(null), NotifyParentProperty(true)]
        public string DataTextValue
        {
            get { return this.dataTextValue; }
            set
            {
                this.dataTextValue = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.DataTextValue;
                }
            }
        }

        /// <summary>
        /// Gets or sets the data text format string.
        /// </summary>
        /// <value>The data text format string.</value>
        [Description("The data text format string."), DefaultValue(null), NotifyParentProperty(true)]
        public string DataTextFormatString
        {
            get { return this.dataTextFormatString; }
            set
            {
                this.dataTextFormatString = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.DataTextFormatString;
                }
            }
        }

        /// <summary>
        /// Gets or sets the data command argument value.
        /// </summary>
        /// <value>The data command argument value.</value>
        [Description("The data command argument value."), DefaultValue(null), NotifyParentProperty(true)]
        public string DataCommandArgumentValue
        {
            get { return this.dataCommandArgumentValue; }
            set
            {
                this.dataCommandArgumentValue = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.DataCommandArgumentValue;
                }
            }
        }

        /// <summary>
        /// Gets or sets the data command argument format string.
        /// </summary>
        /// <value>The data command argument format string.</value>
        [Description("The data command argument format string."), DefaultValue(null), NotifyParentProperty(true)]
        public string DataCommandArgumentFormatString
        {
            get { return this.dataCommandArgumentFormatString; }
            set
            {
                this.dataCommandArgumentFormatString = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.DataCommandArgumentFormatString;
                }
            }
        }

        /// <summary>
        /// Gets or sets the visibility.
        /// </summary>
        /// <value>The visibility.</value>
        [Description("The visibility."), DefaultValue(false), NotifyParentProperty(true)]
        public bool Visible
        {
            get { return this.visible; }
            set
            {
                this.visible = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.Visible;
                }
            }
        }

        /// <summary>
        /// Gets or sets the CSS class.
        /// </summary>
        /// <value>The CSS class.</value>
        [Description("The CSS class."), DefaultValue(null), NotifyParentProperty(true)]
        public string CssClass
        {
            get { return this.cssClass; }
            set
            {
                this.cssClass = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.CssClass;
                }
            }
        }

        /// <summary>
        /// Gets or sets the command name.
        /// </summary>
        /// <value>The command name.</value>
        [Description("The command name."), DefaultValue(null), NotifyParentProperty(true)]
        public string CommandName
        {
            get { return this.commandName; }
            set
            {
                this.commandName = value;
                if ((this as IStateManager).IsTrackingViewState)
                {
                    this.dirtyFlags = this.dirtyFlags | DirtyFlags.CommandName;
                }
            }
        }

        // Nested Types

        private enum DirtyFlags
        {
            None = 0,
            DataTextValue = 1,
            DataTextFormatString = 2,
            DataCommandArgumentValue = 4,
            DataCommandArgumentFormatString = 8,
            Visible = 16,
            CssClass = 32,
            CommandName = 64
        }


        #region IStateManager Members

        /// <summary>
        /// When implemented by a class, gets a value indicating whether a server control is tracking its view state changes.
        /// </summary>
        /// <value></value>
        /// <returns>true if a server control is tracking its view state changes; otherwise, false.</returns>
        bool IStateManager.IsTrackingViewState
        {
            get { return this.IsTrackingViewState; }
        }

        /// <summary>
        /// When implemented by a class, loads the server control's previously saved view state to the control.
        /// </summary>
        /// <param name="state">An <see cref="T:System.Object"></see> that contains the saved view state values for the control.</param>
        void IStateManager.LoadViewState(object state)
        {
            this.LoadViewState(state);
        }

        /// <summary>
        /// When implemented by a class, saves the changes to a server control's view state to an <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// The <see cref="T:System.Object"></see> that contains the view state changes.
        /// </returns>
        object IStateManager.SaveViewState()
        {
            return this.SaveViewState();
        }

        /// <summary>
        /// When implemented by a class, instructs the server control to track changes to its view state.
        /// </summary>
        void IStateManager.TrackViewState()
        {
            this.TrackViewState();
        }

        #endregion

    }

}
